<?php
/**
 * @Author: gan
 * @Description:
 * @File:  MysqlPool
 * @Version: 1.0.0
 * @Date: 2022/1/27 11:55 上午
 */
declare(strict_types=1);

namespace DB;

use DB\Exception\ConnectException;
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
use Swoole\Coroutine\MySQL;

class Pool
{
    private static $instance;
    private static $pool = [];

    private function __construct()
    {
    }

    private function __clone()
    {
    }

    public static function getInstance()
    {
        if (empty(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * 初始化
     * @param string $key
     */
    public function init(string $key)
    {
        $conf             = Manager::$dbConf[$key]['pool']['max'];
        self::$pool[$key] = new Channel($conf);
        while (!self::$pool[$key]->isEmpty()) {
            self::$pool[$key]->pop();
        }
        if (Manager::$dbConf[$key]['pool']['min'] > 0) {
            for ($i = 1; $i <= Manager::$dbConf[$key]['pool']['min']; $i++) {
                Coroutine::create(function () use ($key) {
                    $mysql = Manager::getInstance()->connect($key);
                    if ($mysql->connected && $mysql->errno == 0) {
                        $this->put($key, $mysql);
                    }
                });
            }
        }
    }

    /**
     * 取池
     * @param string $key
     * @return MySQL
     * @throws ConnectException
     */
    public function get(string $key)
    {
        if (!isset(self::$pool[$key])) {
            throw new ConnectException('Mysql Register Not Found');
        }
        if (self::$pool[$key]->isEmpty()) {
            $retry = 0;
            back:
            $retry++;
            $mysql = Manager::getInstance()->connect($key);
            if ($mysql->connected && $mysql->errno == 0) {
                return $mysql;
            } elseif ($retry <= Manager::$dbConf[$key]['pool']['retry']) {
                goto back;
            } else {
                throw new ConnectException('Mysql Get Connection Failed');
            }
        } else {
            return $mysql = self::$pool[$key]->pop();
        }
    }

    /**
     * 回收连接
     * @param $key | 池标志
     * @param $mysql | mysql连接
     */
    public function put($key, $mysql)
    {
        if (self::$pool[$key]->isFull()) {
            self::$pool[$key]->pop();
        }
        self::$pool[$key]->push($mysql);
    }
}
